#pragma once

#include <AVUIEventableObject.h>
#include <AVUIKeyboard.h>

namespace AVUI {

class InputDevice : public EventableObject
{
public:
    DECLARE_ELEMENT(InputDevice, Object);

};

class InputManager;
class TextCompositionManager;
class DeferredElementTreeState;
class KeyboardDevice : public InputDevice
{
    friend class InputManager;
public:
    DECLARE_ELEMENT(KeyboardDevice, InputDevice);

#pragma region Public Methods
    KeyboardDevice(InputManager* pInputManager);

    /// <summary>Sets keyboard focus on the specified element.</summary>
    /// <returns>The element with keyboard focus.</returns>
    /// <param name="element">The element on which to set keyboard focus.</param>
    DependencyObject* Focus(DependencyObject* pElement);

    /// <summary>Gets the set of key states for the specified <see cref="T:System.Windows.Input.Key" />.</summary>
    /// <returns>The set of key states for the specified key.</returns>
    /// <param name="key">The key to check.</param>
    /// <exception cref="T:System.ComponentModel.InvalidEnumArgumentException">
    /// <paramref name="key" /> is not a valid key.</exception>
    KeyStates::Enum GetKeyStates(Key::Enum key);

    /// <summary>Determines whether the specified <see cref="T:System.Windows.Input.Key" /> is in the down state.</summary>
    /// <returns>true if <paramref name="key" /> is in the down state; otherwise, false.</returns>
    /// <param name="key">The key to check.</param>
    /// <exception cref="T:System.ComponentModel.InvalidEnumArgumentException">
    /// <paramref name="key" /> is not a valid key.</exception>
    bool IsKeyDown(Key::Enum key);

    /// <summary>Determines whether the specified <see cref="T:System.Windows.Input.Key" /> is in the toggled state.</summary>
    /// <returns>true if <paramref name="key" /> is in the toggled state; otherwise, false.</returns>
    /// <param name="key">The key to check.</param>
    /// <exception cref="T:System.ComponentModel.InvalidEnumArgumentException">
    /// <paramref name="key" /> is not a valid key.</exception>
    bool IsKeyToggled(Key::Enum key);

    /// <summary>Determines whether the specified <see cref="T:System.Windows.Input.Key" /> is in the up state.</summary>
    /// <returns>true if <paramref name="key" /> is in the up state; otherwise, false.</returns>
    /// <param name="key">The key to check.</param>
    /// <exception cref="T:System.ComponentModel.InvalidEnumArgumentException">
    /// <paramref name="key" /> is not a valid key.</exception>
    bool IsKeyUp(Key::Enum key);

#pragma endregion Public Methods

#pragma region Public Properties

    /// <summary>Gets the element that has keyboard focus. </summary>
    /// <returns>The element with keyboard focus.</returns>
    DependencyObject* get_FocusedElement() { return m_pFocus; }

    /// <summary>Gets the set of <see cref="T:System.Windows.Input.ModifierKeys" /> which are currently pressed.</summary>
    /// <returns>The set of modifier keys.</returns>
    ModifierKeys::Enum get_Modifiers();

#pragma endregion Public Properties

private:

    void Focus(DependencyObject* pFocus, bool askOld, bool askNew);
    void TryChangeFocus(DependencyObject* pNewFocus, bool askOld, bool askNew, bool forceToNullIfFailed);
    void ChangeFocus(DependencyObject* pFocus);
    DeferredElementTreeState* get_FocusTreeState();

    bool KeyDown(Key::Enum keyDown);
    bool KeyUp(Key::Enum keyUp);
    bool KeyChar(Key::Enum keyChar, WCHAR wch);

    TWeakPtr<DependencyObject> m_pActiveSource;
    TWeakPtr<DependencyObject> m_pFocus;
    TWeakPtr<DependencyObject> m_pFocusRootVisual;
    TRefCountedPtr<DeferredElementTreeState> m_pFocusTreeState;
    TWeakPtr<DependencyObject> m_pForceTarget;
    InputManager* m_pInputManager;
    Key::Enum m_previousKey;
    TRefCountedPtr<TextCompositionManager> m_pTextCompositionManager;
};



}; // namespace AVUI






/*
class Keyboard : public Object
{
public:
    Keyboard() : m_isLeftShiftDown(false), m_isRightShiftDown(false), m_isLeftCtrlDown(false), m_isRightCtrlDown(false),
                       m_isLeftAltDown(false), m_isRightAltDown(false) { }

    DECLARE_ELEMENT(Keyboard, Object);
    IMPLEMENT_ROUTED_EVENT(KeyDown, KeyEventArgs, RoutingStrategy::Bubble);
    IMPLEMENT_ROUTED_EVENT(KeyUp, KeyEventArgs, RoutingStrategy::Bubble);
    IMPLEMENT_ROUTED_EVENT(KeyChar, KeyCharEventArgs, RoutingStrategy::Bubble);

    bool KeyDown(Key::Enum keyDown);
    bool KeyUp(Key::Enum keyUp);
    bool KeyChar(Key::Enum keyChar, WCHAR wch);

    void set_KeyboardFocus(Control* pControl);

    ModifierKeys::Enum get_KeyboardModifiers();

    static bool IsFocusable(DependencyObject* pElement);

    KeyboardNavigation* get_KeyboardNavigation() { return &m_navigation; }

    static Keyboard* get_Current();
    static DependencyObject* get_FocusedElement() { return get_Current()->get_FocusedElementInstance(); }
    DependencyObject* get_FocusedElementInstance() { return (DependencyObject*)(Control*)m_pKeyboardFocus; }

    static IInputElement* Focus(IInputElement* pElement) { return NULL; }
 
private:

    void AddEventHandler(const void* pvKey, Delegate* pEventHandler);
    void RemoveEventHandler(const void* pvKey, Delegate* pEventHandler);
    void InvokeEventHandler(const void* pvKey, Object* pSender, Object* pArgs);


    TWeakPtr<Control> m_pKeyboardFocus;
    KeyboardNavigation m_navigation;

    bool m_isLeftShiftDown : 1;
    bool m_isRightShiftDown : 1;
    bool m_isLeftCtrlDown : 1;
    bool m_isRightCtrlDown : 1;
    bool m_isLeftAltDown : 1;
    bool m_isRightAltDown : 1;


};
*/
